package fem2d;

import java.util.ArrayList;

import fem2.AbstractStructuralStaticDemo;
import fem2.Constraint;
import fem2.Element;
import fem2.Face;
import fem2.MaterialModel;
import fem2.Mesh;
import fem2.MeshGenerator;
import fem2.MeshPart;
import fem2.MeshUtilities;
import fem2.Model;
import fem2.Node;
import fem2.StringUtilities;
import fem2.element.StructuralElement;
import fem2.enu.State;
import fem2.material.FluencyCriteria;
import fem2.material.LinearIsotropicHardeningRule;
import fem2.material.LinearKinematicHardeningRule;
import fem2.material.VonMisesMM;
import fem2.mesh_and_topology.SpatialCriteria;
import fem2.mesh_and_topology.SphereSpatialCriteria;
import fem2.observer.GidPlasticityObserver;
import fem2.observer.TimeStepObserver;
import fem2.pre_and_post.GidMeshGenerator;
import fem2.strategies.Strategy;

public class CompressionTest extends AbstractStructuralStaticDemo {

	@Override
	public Mesh createMesh() {
		projectDir = "/home/hbui/kratos_janosch";
		projectName = "compression-test.gid";
		meshFileName = "plane_strain_coarse.msh";
		MeshGenerator mg = new GidMeshGenerator(projectDir + "/" + projectName + "/" + meshFileName);
		return mg.getMesh(2);
	}

	@Override
	public Model createConditions(Model m) {
		Mesh mesh = m.getMesh();

		ArrayList<Node> bottom = MeshUtilities.seekNodesOnSurface(mesh, 0, 1, 0);
		Constraint cxy = new Constraint(false, false);
		MeshUtilities.seekNode(mesh, 0.0, 0.0).setConstraint(cxy);

		Constraint cy = new Constraint(true, false);
		mesh.addConstraint(cy, bottom);

		ArrayList<Node> top = MeshUtilities.seekNodesOnSurface(mesh, 0, 1, -140);

		Constraint cy2 = new Constraint(true, false);
		cy2.setValue(1, -50);
		mesh.setConstraint(cy2, top);

		return m;
	}

	@Override
	public MaterialModel createMaterial(Model m) {
		double E = 20;
		double nu = 0.4;
		double t = 40;

		// MaterialModel mm = new StVenantKirchhoffMM(E, nu, 1.0, 0.0,
		// State.PLANE_STRAIN);

		double ft = 20e-3;
		double K = -50e-3;
		double H = 0;
		FluencyCriteria isoLaw = new LinearIsotropicHardeningRule(ft, K);
		FluencyCriteria kinLaw = new LinearKinematicHardeningRule(H);
		MaterialModel mm = new VonMisesMM(E, nu, t, 0, State.PLANE_STRAIN, isoLaw, kinLaw);
		return mm;
	}

	public MaterialModel createMaterial2(Model m) {
		double E = 15;
		double nu = 0.4;
		double t = 40;

		double ft = 15e-3;
		double K = -50e-3;
		double H = 0;
		FluencyCriteria isoLaw = new LinearIsotropicHardeningRule(ft, K);
		FluencyCriteria kinLaw = new LinearKinematicHardeningRule(H);
		MaterialModel mm = new VonMisesMM(E, nu, t, 0, State.PLANE_STRAIN, isoLaw, kinLaw);

		return mm;
	}

	@Override
	public Element createElement(MeshPart mp, MaterialModel mm) {
		Element e = new StructuralElement(mp, mm);
		// Element e = new EASStructuralElement(mp, mm, EASModeType.Q1E4);
		// Element e = new BBarStructuralElement(mp, mm);
		return e;
	}

	@Override
	public Model createModel() {

		Mesh mesh = createMesh();

		Model m = new Model(mesh);

		MaterialModel mm = createMaterial(m);
		MaterialModel mm2 = createMaterial2(m);

		double x0 = (36 + 40) / 2;
		double y0 = (32.666666666666666 + 28) / 2;
		SpatialCriteria sp = new SphereSpatialCriteria(x0, y0, 0.1);
		for (int i = 0; i < mesh.countFaces(); i++) {
			Face f = mesh.getFace(i);
			double[] c = f.computeCenter();

			Element e;
			if (sp.isSatisfied(c)) {
				e = createElement(f, mm2);
			} else {
				e = createElement(f, mm);

			}
			m.addElement(e);
		}

		m = createConditions(m);

		/*
		 * set the number of fields for structural problem
		 */
		mesh.setNumberOfFields(mesh.getDimension());

		return m;
	}

	@Override
	public void addObservers(Model m, Strategy s, TimeStepObserver o) {
		super.addObservers(m, s, o);

		String meshName = StringUtilities.getFileName(meshFileName);

		s.addObserver(new GidPlasticityObserver(m, o, projectDir, projectName, meshName));
	}

	public static void main(String[] args) {
		AbstractStructuralStaticDemo demo = new CompressionTest();

		demo.run(200);
	}

}
